package com.tuinui.trade.service;

import com.google.appengine.api.datastore.*;
import com.tuinui.trade.entry.EntityMapper;
import com.tuinui.trade.entry.PositionEntry;
import com.tuinui.trade.entry.TransactionEntry;
import com.tuinui.trade.manager.DataManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.util.List;

/**
 * Created with IntelliJ IDEA.
 * User: kaweepapkongkittisan
 * Date: 5/25/13
 * Time: 11:15 AM
 * To change this template use File | Settings | File Templates.
 */
public class StockTransactionService extends EntityMapper  {
    final public static Logger _log = LoggerFactory.getLogger(StockTransactionService.class);

    public static StockTransactionService instance;
    public static StockTransactionService getInstance(){
        if (instance == null){
            instance = new StockTransactionService();
        }
        return instance;
    }
    public void buyStock(PositionEntry position)

    {
        DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();

        Entity positionEntity = convertPositionEntryToEntity(position);
        TransactionEntry transactionEntry = new TransactionEntry();
        transactionEntry.setDate(position.getDate());
        transactionEntry.setAction("BUY");
        transactionEntry.setOwner(position.getOwner());
        transactionEntry.setPrice(position.getPurchasedPrice());
        transactionEntry.setSymbol(position.getSymbol());
        transactionEntry.setVolume(position.getVolume());
        Entity transactionEntity = convertTransactionEntryToEntity(transactionEntry);
        datastore.put(transactionEntity);
        positionEntity.setProperty("transactionId", transactionEntity.getKey().getId());
        position.setTransactionId(transactionEntity.getKey().getId());
        datastore.put(positionEntity);

    }

    /*
        possible cases for selling stocks
        1. Selling transaction match 1 holding position exactly : delete position add sell transaction
        2. Selling transaction volume matches more than one holding position
        3. Selling transaction volume less than oldest holding position


     */
    public void sellStock(PositionEntry positionEntry){
        DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
        //Transaction trx = datastore.beginTransaction(TransactionOptions.Builder.withXG(true));
        sellStock(positionEntry, datastore);
        //trx.commit();
    }

    public void sellStock(PositionEntry positionEntry, DatastoreService datastore){
        //PositionEntry originalPosition = DataManager.getInstance().get


        PositionEntry originalPositionEntry = DataManager.getInstance().getPosition(positionEntry.getId());
        if (positionEntry.getId()>0){

        }
        if (originalPositionEntry!=null && positionEntry.getVolume().equals(originalPositionEntry.getVolume())){
            TransactionEntry transactionEntry = convertPositionEntryToTransactionEntry(positionEntry);
            transactionEntry.setAction("SELL");
            transactionEntry.setOriginalTransaction(positionEntry.getTransactionId());
            Entity transactionEntity = convertTransactionEntryToEntity(transactionEntry);
            Key positionKey =  KeyFactory.createKey("Position", originalPositionEntry.getId());

            datastore.put(transactionEntity);
            datastore.delete(positionKey);

        }else if (originalPositionEntry!=null && positionEntry.getVolume().compareTo(originalPositionEntry.getVolume())<0){
            TransactionEntry transactionEntry = convertPositionEntryToTransactionEntry(positionEntry);
            transactionEntry.setAction("SELL");
            transactionEntry.setOriginalTransaction(positionEntry.getTransactionId());

            Entity transactionEntity = convertTransactionEntryToEntity(transactionEntry);
            Key positionKey =  KeyFactory.createKey("Position", positionEntry.getId());
            Query query = new Query("Position", positionKey);
            Entity positionEntity = datastore.prepare(query).asSingleEntity();
            BigDecimal remainingVolume = originalPositionEntry.getVolume().subtract(positionEntry.getVolume());
            positionEntity.setProperty("volume", remainingVolume.doubleValue());
            datastore.put(transactionEntity);
            datastore.put(positionEntity);

        }else if (originalPositionEntry!=null && positionEntry.getVolume().compareTo(originalPositionEntry.getVolume())>0){
            List<PositionEntry> availablePositions = getAvailablePosition(positionEntry.getSymbol(), positionEntry.getOwner());
            BigDecimal remainingVolume = positionEntry.getVolume();
            _log.debug("selling multiple positions");
            for(PositionEntry partialPosition: availablePositions){
                if (remainingVolume.compareTo(BigDecimal.ZERO)>0){
                    if (remainingVolume.compareTo(partialPosition.getVolume())>=0){
                        _log.debug("Sell the whole position");
                        partialPosition.setPurchasedPrice(positionEntry.getPurchasedPrice());
                        sellStock(partialPosition, datastore);
                    }else{
                        _log.debug("Sell part of position");
                        partialPosition.setVolume(remainingVolume);
                        partialPosition.setPurchasedPrice(positionEntry.getPurchasedPrice());
                        sellStock(partialPosition, datastore);

                    }
                    remainingVolume = remainingVolume.subtract(partialPosition.getVolume());
                }
            }

        }
    }

    public void deletePosition(PositionEntry positionEntry){

        DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();

        Key positionKey =  KeyFactory.createKey("Position", positionEntry.getId());
        if (positionEntry.getTransactionId()!=0){
            Key transactionKey = KeyFactory.createKey("Transaction", positionEntry.getTransactionId());
            datastore.delete(positionKey, transactionKey);
        }else{
            datastore.delete(positionKey);
        }

    }

    public void updatePosition(PositionEntry positionEntry) {

        DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();

        Key positionKey =  KeyFactory.createKey("Position", positionEntry.getId());
        Query query = new Query(positionKey);
        Entity newPositionEntity = convertPositionEntryToEntity(positionEntry);
        Entity originalPositionEntity = datastore.prepare(query).asSingleEntity();

        PositionEntry originalPositionEntry = convertEntityToPositionEntry(originalPositionEntity);
        PositionEntry newPositionEntry = convertEntityToPositionEntry(newPositionEntity);
        if (positionEntry.getTransactionId()!=0){
            Key transactionKey = KeyFactory.createKey("Transaction", positionEntry.getTransactionId());

            query = new Query(transactionKey);
            Entity transactionEntity = datastore.prepare(query).asSingleEntity();
            TransactionEntry transactionEntry = convertEntityToTransactionEntry(transactionEntity);
            //if (transactionEntry.getVolume().equals(originalPositionEntry.getVolume())){
                transactionEntity.setProperty("symbol", positionEntry.getSymbol());
                transactionEntity.setProperty("date", positionEntry.getDate());
                transactionEntity.setProperty("owner", positionEntry.getOwner());
                transactionEntity.setProperty("price", convertValue(positionEntry.getPurchasedPrice()));
                transactionEntity.setProperty("volume", convertValue(positionEntry.getVolume()));
                datastore.put(transactionEntity);
            //}
        }

        originalPositionEntity.setProperty("symbol", positionEntry.getSymbol());
        originalPositionEntity.setProperty("date", positionEntry.getDate());
        originalPositionEntity.setProperty("owner", positionEntry.getOwner());
        originalPositionEntity.setProperty("purchasedPrice", convertValue(positionEntry.getPurchasedPrice()));
        originalPositionEntity.setProperty("volume", convertValue(positionEntry.getVolume()));

        datastore.put(originalPositionEntity);

    }


    public List<PositionEntry> getAvailablePosition(String symbol, String owner){
        DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
        _log.debug("get available position for " + symbol + " owner: "  + owner);

        Query query = new Query("Position")
                .addFilter("symbol", Query.FilterOperator.EQUAL, symbol)
                .addFilter("owner", Query.FilterOperator.EQUAL, owner)
                .addSort("date", Query.SortDirection.ASCENDING);
        List<Entity> entities = datastore.prepare(query).asList(FetchOptions.Builder.withDefaults());

        _log.debug("query result for available positions: " + entities.size());
        List<PositionEntry> positions = convertEntityToPositionEntry(entities);
        _log.debug("query result for available positions: " + positions.size());
        return positions;

    }

    public BigDecimal countAvailableShares(List<PositionEntry> list){
        BigDecimal availableShares = new BigDecimal(0);
        for(PositionEntry entry: list){
            availableShares = availableShares.add(entry.getVolume());
        }
        return availableShares;
    }


}
